package frege.control.comonad.Extend where


--import Prelude hiding (id, (.))
--import Control.Category
import frege.data.wrapper.Identity
--import Data.Functor.Identity
import frege.control.Monoid
--import Data.List (tails)
import frege.data.NonEmpty (NonEmpty, |:)
--import Data.Sequence (Seq) 
--import qualified Data.Sequence as Seq
--import Data.Tree
import frege.data.List (tails)

infixl 1 `=>>` 
infixr 1 `<<=` `=<=` `=>=` 

{-- 

There are two ways to define an 'Extend' instance:

I. Provide definitions for 'extend'
satisfying this law:

> extend f <~ extend g = extend (f <~ extend g)

II. Alternately, you may choose to provide definitions for 'duplicate' 
satisfying this laws:

> duplicate <~ duplicate    = fmap duplicate <~ duplicate

These are both equivalent to the statement that (=>=) is associative

> (f =>= g) =>= h = f =>= (g =>= h)

You may of course, choose to define both 'duplicate' and 'extend'. 
In that case you must also satisfy these laws:

> extend f  = fmap f <~ duplicate
> duplicate = extend id

These are the default definitions of 'extend' and 'duplicate'.

-}


class Extend Functor w => w where
  -- duplicate = extend id
  -- fmap (fmap f) <~ duplicate = duplicate <~ fmap f
  duplicate :: w a -> w (w a)
  duplicate x = extend id x
   
  --extend f = fmap f <~ duplicate
  extend :: (w a -> b) -> w a -> w b
  extend f x = fmap f $ duplicate x

--- 'extend' with the arguments swapped. Dual to '>>=' for a 'Monad'.
(=>>) :: Extend w => w a -> (w a -> b) -> w b
x =>> f = extend f x

--- 'extend' in operator form 
(<<=) :: Extend w => (w a -> b) -> w a -> w b
f <<= x = extend f x

--- Right-to-left Cokleisli composition 
(=<=) :: Extend w => (w b -> c) -> (w a -> b) -> w a -> c
f =<= g = f <~ extend g

--- Left-to-right Cokleisli composition
(=>=) :: Extend w => (w a -> b) -> (w b -> c) -> w a -> c
f =>= g = g <~ extend f 

-- * Extends for Prelude types:
--
-- Instances: While Data.Functor.Extend.Instances would be symmetric
-- to the definition of Control.Monad.Instances in base, the reason
-- the latter exists is because of Haskell 98 specifying the types
-- @'Either' a@, @((,)m)@ and @((->)e)@ and the class Monad without
-- having the foresight to require or allow instances between them.
--
-- Here Haskell 98 says nothing about Extend, so we can include the
-- instances directly avoiding the wart of orphan instances.

instance Extend [] where
  duplicate xs = tails xs
  
instance Extend Maybe where
  duplicate Nothing = Nothing
  duplicate j = Just j

instance Extend (Either a) where
  --WTF???
  -- fmap = Monad.fmap
  duplicate (Left a) = Left a
  duplicate r = Right r

instance Extend ((,) e) where
  duplicate p = (fst p, p)
  
--instance Functor ((->) m) where
--  fmap f g = f <~ g 

--instance Extend Semigroup m => ((->) m) where
--  duplicate f m = f <~ (<>) m

--instance Extend Seq where
--  duplicate = Seq <~ tails

--instance Extend Tree where
--  duplicate (w@ Node _ as) = Node w (map duplicate as)

-- I can't fix the world
-- instance (Monoid m, Extend n) => Extend (ReaderT m n) 
--   duplicate f m = f . mappend m

-- * Extends for types from 'transformers'.
--
-- This isn't really a transformer, so i have no compunction about including the instance here.
--
-- TODO: Petition to move Data.Functor.Identity into base
instance Extend Identity where
  duplicate x = Identity x

-- Provided to avoid an orphan instance. Not proposed to standardize. 
-- If Extend moved to base, consider moving instance into transformers?
--instance Extend Extend w => IdentityT w where
--  extend f (IdentityT m) = IdentityT (extend (f <~ IdentityT) m)

instance Extend NonEmpty where
  extend f (w@ NonEmpty _ aas) = f w |: 
      (case aas of
        []     -> []
        (a:as) -> toList (extend f (a |: as))
      )  
      
       



